package org.dromara.solonplugins.old.shardingjdbc;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.noear.solon.core.AopContext;
import org.noear.solon.core.Plugin;
import org.noear.solon.core.Props;
import org.noear.solon.core.event.AppLoadEndEvent;
import org.noear.solon.core.event.EventBus;
import org.noear.solon.core.util.ResourceUtil;

import io.shardingjdbc.core.api.ShardingDataSourceFactory;

/**
 * Solon插件入口
 *
 * @author: aoshiguchen
 */
public class XPluginImp implements Plugin {
    @Override
    public void start(AopContext context) throws Throwable {
    	Props props = context.cfg();
    	String TAG = "shardingjdbc";
    	String PROP_PATH = props.get(TAG+".path", "shardingjdbc.yaml");//配置文件路径,默认shardingjdbc.yaml
    	String dbs = props.get(TAG+"db");
    	
    	URL yamlFile = ResourceUtil.getResource(PROP_PATH);
    	InputStream ins = yamlFile.openStream();
    	if(ins!=null && ins.available()>1) {
    		ByteArrayOutputStream out = new ByteArrayOutputStream();
        	int bufferSize = 8192;
        	write(out, ins, -1, bufferSize);
        	byte[] bytes = out.toByteArray();
        	
        	Map<String, DataSource> dataSourceMap = new HashMap<>();
        	
        	//监听DataSource数据源初始化事件
            context.subWrapsOfType(DataSource.class, bw->{
            	dataSourceMap.put(bw.name(), bw.raw());
            });
            
    		// 晚点启动，让扫描时产生的组件可以注册进来
    		EventBus.subscribe(AppLoadEndEvent.class, e -> {
    			DataSource ds = ShardingDataSourceFactory.createDataSource(dataSourceMap, bytes);
    		});
    		
    		ins.close();
    		out.close();
    	}
    }

    /**
     * 将输入流写入一个输出流。
     * <p>
     * <b style=color:red>注意</b>，它并不会关闭输入/出流
     * 
     * @param ops
     *            输出流
     * @param ins
     *            输入流
     * @param limit
     *            最多写入多少字节，0 或负数表示不限
     * @param bufferSize
     *            缓冲块大小
     * 
     * @return 写入的字节数
     * 
     * @throws IOException
     */
    private static long write(OutputStream ops, InputStream ins, long limit, int bufferSize)
            throws IOException {
        if (null == ops || null == ins)
            return 0;

        byte[] buf = new byte[bufferSize];
        int len;
        long bytesCount = 0;
        if (limit > 0) {
            long remain = limit;
            while (-1 != (len = ins.read(buf))) {
                // 还可以写入的字节数
                if (len > remain) {
                    len = (int) remain;
                    remain = 0;
                }
                // 减去
                else {
                    remain -= len;
                }
                bytesCount += len;
                ops.write(buf, 0, len);
                // 写够了
                if (remain <= 0) {
                    break;
                }
            }
        }
        // 全写
        else {
            while (-1 != (len = ins.read(buf))) {
                bytesCount += len;
                ops.write(buf, 0, len);
            }
        }
        // 啥都没写，强制触发一下写
        // 这是考虑到 walnut 的输出流实现，比如你写一个空文件
        // 那么输入流就是空的，但是 walnut 的包裹输出流并不知道你写过了
        // 它人你就是打开一个输出流，然后再关上，所以自然不会对内容做改动
        // 所以这里触发一个写，它就知道，喔你要写个空喔。
        if (0 == bytesCount) {
            ops.write(buf, 0, 0);
        }
        ops.flush();
        return bytesCount;
    }

    
}
